package org.matchit.converter.bean;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.core.convert.converter.Converter;

/**
 * Convert a bean into its current property value.
 * 
 * @author Jeroen van Schagen
 * @since 20-03-2011
 *
 * @param <B> type of beans being converted
 * @param <P> type of property value, provided as output
 */
public class BeanToPropertyConverter<B, P> implements Converter<B, P> {
    private final String propertyName;

    /**
     * Construct a new {@link BeanToPropertyConverter}.
     * @param propertyName name of the property being converted into
     */
    public BeanToPropertyConverter(String propertyName) {
        this.propertyName = propertyName;
    }

    /**
     * Construct a new {@link BeanToPropertyConverter}.
     * @param <B> type of beans being converted
     * @param <P> type of property value, provided as output
     * @param propertyName name of the property being converted into
     * @return new converter instance
     */
    public static <B, P> BeanToPropertyConverter<B, P> property(String propertyName) {
        return new BeanToPropertyConverter<B, P>(propertyName);
    }

    /**
     * Construct a new (type-safe) {@link BeanToPropertyConverter}.
     * @param <B> type of beans being converted
     * @param <P> type of property value, provided as output
     * @param propertyName name of the property being converted into
     * @param propertyClass type of the property being converted into
     * @return new converter instance
     */
    public static <B, P> BeanToPropertyConverter<B, P> property(String propertyName, Class<P> propertyClass) {
        return new BeanToPropertyConverter<B, P>(propertyName);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @SuppressWarnings("unchecked")
    public P convert(B bean) {
        BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(bean);
        Object property = beanWrapper.getPropertyValue(propertyName);
        return (P) property;
    }
}
